﻿using Justin.BI.TestDataTools.DAL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using Justin.BI.TestDataTools.Models;
using Justin.BI.TestDataTools.Settings;
using Justin.BI.TestDataTools.Utility;
using Justin.FrameWork.Helper;

namespace Justin.BI.TestDataTools
{
    public partial class testDataGeneratorTool : Form
    {
        public testDataGeneratorTool()
        {
            InitializeComponent();
        }

        MSSQLTableDAL tableDal = new MSSQLTableDAL();

        private JTable Table
        {
            get
            {
                JTable table = tvDst.Tag as JTable;
                return table;
            }
            set
            {
                tvDst.Tag = value;
            }
        }
        private List<DBTable> DataSource
        {
            get
            {
                List<DBTable> tables = tvSource.Tag as List<DBTable>;
                return tables;
            }
            set
            {
                tvSource.Tag = value;
            }
        }

        #region 数据绑定

        private void BindTable(JTable table)
        {
            tvDst.Nodes.Clear();

            var tableNode = new TreeNode(table.TableName);
            foreach (var field in table.Fields.OrderBy(row => row.FieldName))
            {
                var fieldNode = new TreeNode(field.FieldName);
                if (!field.Visible)
                {
                    fieldNode.ForeColor = Color.Red;
                }
                tableNode.Nodes.Add(fieldNode);
            }
            tvDst.Nodes.Add(tableNode);

            tvDst.ExpandAll();

        }
        private void BindFieldInfo(JField field)
        {
            if (field != null)
            {
                lbFieldName.Text = field.FieldName;
            }
            cBoxValueType.Text = field.ValueType.ToJString();
            cBoxValueCategroy.Text = field.SourceInfo.SourceValueCategroy.ToJString();
            cBoxVisible.Text = field.Visible.ToJString("True");
            txtMinValue.Text = field.SourceInfo.MinValue.ToJString();
            txtMaxValue.Text = field.SourceInfo.MaxValue.ToJString();
            txtSeed.Text = field.SourceInfo.Step.ToJString();
            txtFormat.Text = field.Format.ToJString();
            string sourceStr = "";
            foreach (var item in field.SourceInfo.Sources)
            {
                sourceStr += item.ToString() + "," + Environment.NewLine;
            }
            if (sourceStr.Length > 0)
            {
                txtSourceList.Text = sourceStr.Remove(sourceStr.Length - 1, 1);
            }
            else
            {
                txtSourceList.Clear();
            }
            txtRefTableName.Text = field.SourceInfo.ReferenceTableName;
            txtRefFieldName.Text = field.SourceInfo.ReferenceColumnName;
            txtFilter.Text = field.SourceInfo.RefFilter;
            checkBoxFromTableValueCalculateUseOtherField.Checked = field.SourceInfo.FromTableCalculateValueUseOtherField;

            cBoxOtherFieldName.Text = field.SourceInfo.OtherFiledName;
            cBoxOtherFieldCalculate.Text = field.SourceInfo.OtherFiledCalculate;
            txtOtherFieldCalculateValue.Text = field.SourceInfo.OtherFiledCalculateValue.ToJString("0");
            checkRandOtherFieCalculateValue.Checked = field.SourceInfo.RandOtherFiledCalculateValue;

            SelectTbSourceIndex(field.SourceInfo.SourceValueCategroy);
        }
        private void BindTableInfo(JTable table)
        {
            lbTableName.Text = table.TableName;
            txtDataCount.Text = table.DataCount.ToJString();
            txtBeforeSQL.Text = table.BeforeSQL;
            txtAfterSQL.Text = table.AfterSQL;

            cBoxOtherFieldName.DataSource = table.Fields.Select(row => row.FieldName).ToList();
        }

        #endregion

        #region 辅助函数

        private JField GetFieldInfo(string tableName, string fieldName)
        {
            return Table.Fields.Where(f => f.FieldName == fieldName).FirstOrDefault();
        }
        private JTable GetTable(string tableName)
        {
            return Table;// tables.Where(row => row.TableName == tableName).FirstOrDefault();
        }
        private void SelectTbSourceIndex(JSourceValueCategroy sourceValueCategroy)
        {
            switch (sourceValueCategroy)
            {
                case JSourceValueCategroy.List: tbSourceInfo.SelectedIndex = 0; break;
                case JSourceValueCategroy.Range: tbSourceInfo.SelectedIndex = 1; break;
                case JSourceValueCategroy.Sequence: tbSourceInfo.SelectedIndex = 1; break;
                case JSourceValueCategroy.FromTable: tbSourceInfo.SelectedIndex = 2; break;
                case JSourceValueCategroy.OtherField: tbSourceInfo.SelectedIndex = 3; break;
            }
        }
        public string Serialize<T>(T obj)
        {
            if (obj == null) return null;
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            MemoryStream stream = new MemoryStream();
            XmlTextWriter xtw = new XmlTextWriter(stream, Encoding.UTF8);
            xtw.Formatting = Formatting.Indented;
            try
            {
                serializer.Serialize(stream, obj);
            }
            catch { return null; }
            stream.Position = 0;
            string returnStr = string.Empty;
            using (StreamReader sr = new StreamReader(stream, Encoding.UTF8))
            {
                string line = "";
                while ((line = sr.ReadLine()) != null)
                {
                    returnStr += line + Environment.NewLine;
                }
            }
            return returnStr;
        }
        public T Deserialize<T>(string data)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                using (StreamWriter sw = new StreamWriter(stream, Encoding.UTF8))
                {
                    sw.Write(data);
                    sw.Flush();
                    stream.Seek(0, SeekOrigin.Begin);
                    XmlSerializer serializer = new XmlSerializer(typeof(T));
                    try
                    {
                        var obj = serializer.Deserialize(stream);
                        return ((T)obj);
                    }
                    catch { return default(T); }
                }
            }
        }
        private string GetFileName(string tableName, FileType fileType)
        {
            string fileName = string.Format(fileType == FileType.Config ? Constants.ConfigFileNameFormat : Constants.OuputSQLFileNameFormat, tableName);
            return fileName;
        }


        #endregion
        #region 功能函数

        private void LoadSetting(string tableName)
        {
            string fileName = GetFileName(tableName, FileType.Config);
            string s = File.ReadAllText(fileName, Encoding.UTF8);
            Table = Deserialize<JTable>(s);
            BindTable(Table);
        }
        private void SaveSettings(JTable table)
        {
            string fileName = GetFileName(Table.TableName, FileType.Config);
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }
            if (table != null)
            {
                string s = Serialize<JTable>(table);
                File.AppendAllText(fileName, s, Encoding.UTF8);
            }
            message.Text = string.Format("成功保存表{0}数据生成配置", table.TableName);
        }
        private bool CheckTableSetting()
        {
            string message = "";

            if (Table.DataCount > 0)
            {
                foreach (var field in Table.Fields)
                {
                    if (field.SourceInfo == null && field.SourceInfo.SourceValueCategroy == null)
                    {
                        message += string.Format("{0}:{1}需设置SourceValueCategroy", Table.TableName, field.FieldName) + Environment.NewLine;
                    }
                }
            }
            txtMessage.Text = message;
            return string.IsNullOrEmpty(message);
        }
        public void Mock(StringBuilder sqlBuilder, JTable table)
        {
            string fileName = GetFileName(table.TableName, FileType.SQL);
            File.AppendAllText(fileName, sqlBuilder.ToString());
        }

        #endregion

        #region TtvSource事件

        private void tvSource_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            tvSource.SelectedNode = e.Node;
        }
        private void loadMenuItemOfTVSource_Click(object sender, EventArgs e)
        {
            string tableName = "";
            if (tvSource.SelectedNode.Parent != null)
            {
                tableName = tvSource.SelectedNode.Parent.Text;
            }
            else
            {
                tableName = tvSource.SelectedNode.Text;
            }
            LoadSetting(tableName);
            BindTableInfo(Table);
        }
        private void TranslateMenuItemOfTVSource_Click(object sender, EventArgs e)
        {
            string tableName = "";
            if (tvSource.SelectedNode.Parent != null)
            {
                tableName = tvSource.SelectedNode.Parent.Text;
            }
            else
            {
                tableName = tvSource.SelectedNode.Text;
            }

            DBTable dbTable = DataSource.Where(row => row.TableName == tableName).FirstOrDefault();
            if (dbTable != null)
            {
                Table = new JTable(dbTable);
                BindTable(Table);
                BindTableInfo(Table);
            }
        }

        #endregion
        #region tvDst事件

        private void tvDst_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            tvDst.SelectedNode = e.Node;
        }
        private void visualeMenuItemOfDst_Click(object sender, EventArgs e)
        {
            try
            {
                if (tvDst.SelectedNode.Parent != null)
                {
                    string fieldName = tvDst.SelectedNode.Text;
                    string tableName = tvDst.SelectedNode.Parent.Text;
                    JField field = GetFieldInfo(tableName, fieldName);
                    field.SetVisible(!field.Visible);
                    BindFieldInfo(field);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "设置是否生成该列数据", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void tvDst_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (tvDst.SelectedNode.Parent != null)
            {
                string fieldName = tvDst.SelectedNode.Text;
                string tableName = tvDst.SelectedNode.Parent.Text;
                JField field = GetFieldInfo(tableName, fieldName);
                BindFieldInfo(field);
                BindTableInfo(GetTable(tableName));
                tabControl1.SelectedIndex = 0;
            }
            else
            {
                string tableName = tvDst.SelectedNode.Text;
                BindTableInfo(GetTable(tableName));
                tabControl1.SelectedIndex = 1;
            }
        }


        #endregion
        #region Field信息设置事件

        private void cBoxValueCategroy_SelectedIndexChanged(object sender, EventArgs e)
        {
            JSourceValueCategroy sourceValueCategroy = (JSourceValueCategroy)Enum.Parse(typeof(JSourceValueCategroy), cBoxValueCategroy.Text, true);
            SelectTbSourceIndex(sourceValueCategroy);
        }


        #endregion
        #region 按钮事件

        private void btnDataSourceChoose_Click(object sender, EventArgs e)
        {
            SqlHelper.ConnStr = "Data Source=.;Initial Catalog=gtp-default;Integrated Security=True"; //DBConnectDialog.GetConnectionString();

            tvAllTables.Nodes.Clear();
            foreach (var item in tableDal.GetAllTables().Where(row => row.StartsWith("T_VR_")))
            {
                tvAllTables.Nodes.Add(item);
            }
        }
        private void btnPrepareDBTables_Click(object sender, EventArgs e)
        {
            List<string> tableNames = new List<string>();
            foreach (TreeNode item in tvAllTables.Nodes)
            {
                if (item.Checked)
                {
                    tableNames.Add(item.Text);
                }
            }

            tvSource.Nodes.Clear();
            DataSource = tableDal.GetAllTableSchema(tableNames);
            foreach (var item in DataSource)
            {
                var tableNode = new TreeNode(item.TableName);
                if (item.PrimaryKey != null)
                    tableNode.Nodes.Add(new TreeNode("PK_" + item.PrimaryKey.ColumnName));

                foreach (var fk in item.ForeignKeys)
                {
                    tableNode.Nodes.Add(new TreeNode("FK_" + fk.ColumnName));
                }

                foreach (var column in item.Columns)
                {
                    tableNode.Nodes.Add(new TreeNode("___" + column.ColumnName));

                }

                tvSource.Nodes.Add(tableNode);

            }
        }
        private void btnSaveFieldInfo_Click(object sender, EventArgs e)
        {
            try
            {
                string tableName = "";
                JTable table = GetTable(tableName);
                string fieldName = tvDst.SelectedNode.Text;
                tableName = tvDst.SelectedNode.Parent.Text;
                JField field = GetFieldInfo(tableName, fieldName);
                field.ValueType = (JValueType)Enum.Parse(typeof(JValueType), cBoxValueType.Text, true);
                field.SourceInfo.SourceValueCategroy = (JSourceValueCategroy)Enum.Parse(typeof(JSourceValueCategroy), cBoxValueCategroy.Text, true);
                field.SetVisible(bool.Parse(cBoxVisible.Text));
                field.SourceInfo.MinValue = txtMinValue.Text;
                field.SourceInfo.MaxValue = txtMaxValue.Text;
                field.SourceInfo.Step = txtSeed.Text;
                field.Format = txtFormat.Text;
                if (string.IsNullOrEmpty(txtSourceList.Text))
                {
                    field.SourceInfo.Sources = new List<object>();
                }
                else
                {
                    string sourceString = txtSourceList.Text.Trim().TrimEnd(',');
                    field.SourceInfo.Sources = sourceString.Split(',').Where(row => !string.IsNullOrEmpty(row.Trim())).Select(row => (object)row.Trim()).ToList();
                }

                field.SourceInfo.ReferenceTableName = txtRefTableName.Text;
                field.SourceInfo.ReferenceColumnName = txtRefFieldName.Text;
                field.SourceInfo.RefFilter = txtFilter.Text;
                field.SourceInfo.FromTableCalculateValueUseOtherField = checkBoxFromTableValueCalculateUseOtherField.Checked;

                field.SourceInfo.OtherFiledName = cBoxOtherFieldName.Text;
                field.SourceInfo.OtherFiledCalculate = cBoxOtherFieldCalculate.Text;
                field.SourceInfo.OtherFiledCalculateValue = int.Parse(txtOtherFieldCalculateValue.Text);
                field.SourceInfo.RandOtherFiledCalculateValue = checkRandOtherFieCalculateValue.Checked;
                if (field.SourceInfo.SourceValueCategroy == JSourceValueCategroy.OtherField)
                {
                    field.Order = table.Order;
                    table.Order = table.Order + 1;
                }

                if (table.DataCount == 0)
                {
                    tabControl1.SelectedIndex = 1;
                }
                tvDst.SelectedNode.ForeColor = Color.Green;
                message.Text = string.Format("成功配置字段{0}，该表配置完成后，请保存配置", fieldName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "设置生成规则失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }


        }
        private void btnSaveTable_Click(object sender, EventArgs e)
        {
            if (tvDst.SelectedNode != null)
            {
                string tableName = "";
                if (tvDst.SelectedNode.Parent == null)
                {
                    tableName = tvDst.SelectedNode.Text;
                }
                else
                {
                    tableName = tvDst.SelectedNode.Parent.Text;
                }
                JTable table = GetTable(tableName);
                table.DataCount = int.Parse(txtDataCount.Text);
                table.BeforeSQL = txtBeforeSQL.Text;
                table.AfterSQL = txtAfterSQL.Text;
            }
            message.Text = string.Format("成功配置表{0}，该表配置完成后，请保存配置", Table.TableName);
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            //XmlSerializer xmls = new XmlSerializer(typeof(List<JTable>));
            //StringWriter sw = new StringWriter();
            //xmls.Serialize(sw, tables);
            SaveSettings(Table);

        }
        private void btnGenerateData_Click(object sender, EventArgs e)
        {
            if (!CheckTableSetting())
            {
                return;
            }
            string fileName = GetFileName(Table.TableName, FileType.SQL);
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }
            Table.Process();
            message.Text = string.Format("成功生成表{0}插入数据SQL", Table.TableName);

        }

        #endregion
        private void fomr1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult result = MessageBox.Show("是否保存设置？", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            if (result == DialogResult.OK)
            {
                SaveSettings(Table);
            }
        }


        private void fomr1_Load(object sender, EventArgs e)
        {
            message.Text = "状态栏";
            JTable.SqlProcess = Mock;
        }

        private void btnBrowerSQLFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Constants.OuputSQLFileFolder;
            openFileDialog.Filter = "SQL文件|*.sql|所有文件|*.*";
            openFileDialog.RestoreDirectory = true;
            openFileDialog.FilterIndex = 1;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string fileName = openFileDialog.FileName;
                using (StreamReader sr = new StreamReader(fileName, Encoding.Default))
                {

                    StringBuilder builder = new StringBuilder();
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        builder.Append(line).AppendLine();
                        if (builder.Length > Constants.SqlBufferSize)
                        {
                            SqlHelper.ExecuteNonQuery(SqlHelper.ConnStr, CommandType.Text, builder.ToString(), null);
                            builder.Clear();
                        }
                    }
                    if (builder.Length > 0)
                    {
                        SqlHelper.ExecuteNonQuery(SqlHelper.ConnStr, CommandType.Text, builder.ToString(), null);
                        builder.Clear();
                    }
                    sr.Close();
                }
            }
            MessageBox.Show("Execute SQL Finished！");
        }

    }


    public enum FileType
    {
        Config,
        SQL
    }
}
